package com.shekhar.paas.story;

import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.UUID;

import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import twitter4j.Tweet;
import twitter4j.URLEntity;

import com.shekhar.paas.domain.Story;
import com.shekhar.paas.exceptions.StoryCreationException;
import com.shekhar.paas.twitter.utils.TwitterUtils;
import com.shekhar.paas.util.TitleCleaner;
import com.shekhar.paas.util.UrlCleaner;

import de.l3s.boilerpipe.document.TextDocument;
import de.l3s.boilerpipe.extractors.ArticleExtractor;
import de.l3s.boilerpipe.sax.BoilerpipeSAXInput;
import de.l3s.boilerpipe.sax.HTMLFetcher;

@Component
public class TweetStoryCreator implements StoryCreator {

    private Logger logger = Logger.getLogger(this.getClass());

    @Override
    public List<Story> createNewStory(Tweet tweet, String searchTerm) {
        logger.debug("Processing tweet " + tweet.getText());
        URLEntity[] urlEntities = tweet.getURLEntities();
        if (ArrayUtils.isEmpty(urlEntities)) {
            return Collections.<Story> emptyList();
        }
        if (isSearchTermOnlyInUrl(tweet, searchTerm)) {
            return Collections.<Story> emptyList();
        }
        List<String> urls = extractLongUrls(urlEntities);
        urls = UrlCleaner.clean(urls);
        if (CollectionUtils.isEmpty(urls)) {
            return Collections.<Story> emptyList();
        }
        List<Story> stories = new ArrayList<Story>();

        String[] tags = TwitterUtils.hashTags(tweet.getHashtagEntities()).toArray(new String[0]);
        tags = ArrayUtils.add(tags, searchTerm);
        for (String url : urls) {
            Story story = new Story();
            try {
                TextDocument textDocument = new BoilerpipeSAXInput(HTMLFetcher.fetch(new URL(url)).toInputSource()).getTextDocument();
                String title = textDocument.getTitle();
                if (StringUtils.isBlank(title) || StringUtils.equalsIgnoreCase("Redirect Notice", title)
                        || StringUtils.equalsIgnoreCase("Cannot find server", title)) {
                    logger.warn("Not creating story for url " + url);
                    continue;
                }
                title = TitleCleaner.clean(title, url);
                ArticleExtractor.INSTANCE.process(textDocument);
                String text = textDocument.getContent();
                if (StringUtils.isBlank(text)) {
                    logger.warn("Not creating story for url " + url);
                    continue;
                }
                story.setTitle(title);
                story.setText(removeLines(text));
            } catch (Exception e) {
                throw new StoryCreationException(e, tweet.getText(), story.getUrl());
            }
            story.setUrl(url);
            story.setCreationDate(new Date());
            if (TwitterUtils.isRetweet(tweet.getText())) {
                story.setRetweetCount(1);
            } else {
                story.setTweetCount(1);
            }
            story.setTags(tags);
            story.setTweets(new com.shekhar.paas.domain.Tweet[] {
                    TweetBuilder.tweet()
                            .withCreatedAt(tweet.getCreatedAt())
                            .withFromUser(tweet.getFromUser())
                            .withId(tweet.getId())
                            .withProfileImageUrl(tweet.getProfileImageUrl())
                            .withText(tweet.getText())
                            .withIsoLanguageCode(tweet.getIsoLanguageCode())
                            .build() });
            story.setLastUpdatedOn(new Date());
            story.setScore(new StoryScorer().score(story));
            story.setId(UUID.randomUUID().toString());
            stories.add(story);
        }
        return stories;
    }

    public boolean isSearchTermOnlyInUrl(Tweet tweet, String searchTerm) {
        URLEntity[] urlEntities = tweet.getURLEntities();
        String tweetText = tweet.getText();
        for (URLEntity urlEntity : urlEntities) {
            tweetText = StringUtils.remove(tweetText, urlEntity.getURL().toString());
        }
        if (StringUtils.containsIgnoreCase(tweetText, searchTerm)) {
            return false;
        }
        return true;
    }

    private String removeLines(String text) {
        String[] lines = text.split("\\n");
        int startIndex = lines.length < 2 ? 0 : 2;
        int endIndex = lines.length < 2 ? lines.length : startIndex + 3;
        return StringUtils.join(Arrays.copyOfRange(lines, startIndex, endIndex));
    }

    private List<String> extractLongUrls(URLEntity[] urlEntities) {
        List<String> urls = new ArrayList<String>();
        for (URLEntity urlEntity : urlEntities) {
            URL expandedUrl = urlEntity.getExpandedURL();
            String actualUrl = null;
            try {
                actualUrl = TwitterUtils.convertShortUrlToLongUrl(expandedUrl);
            } catch (IOException e) {
                logger.warn("Got exception while trying to get the actual url ", e);
                continue;
            }
            if (actualUrl != null) {
                urls.add(actualUrl);
            }
        }
        return urls;
    }

}
